//
// Created by lyk on 22-9-25.
//

#ifndef MATRIX_DOT_H
#define MATRIX_DOT_H


#include <random>
#include <chrono>
#include <iostream>

#define TEST_NUM 10

float dotBaseline(const float *a, const float *b, int len) {
    float result = 0;
    for (size_t i = 0; i < len; ++i)
        result += a[i] * b[i];
    return result;
}

float dotWinergrad(const float *a, const float *b, int len) {
    float result = 0;
    if (len % 2 == 1) {
        len -= 1;
        result += a[len] * b[len];
    }
    for (size_t i = 0; i < len; i += 2) {
        result += (a[i] + b[i + 1]) * (a[i + 1] + b[i]) - a[i] * a[i + 1] - b[i] * b[i + 1];
    }
    return result;
}

void timeDot(
        float (func)(const float *, const float *, int), const std::string &func_name,
        const float *A, const float *B, int len) {
    auto t1 = std::chrono::system_clock::now();
    for (int i = 0; i < TEST_NUM; ++i)
        func(A, B, len);
    auto t2 = std::chrono::system_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::duration<double >>(t2 - t1);
    std::cout << func_name << " " << func(A, B, len) << " cost: " << duration.count() / TEST_NUM << "s" << std::endl;
}

void testDot(int len) {
    auto arr1 = new float[len];
    auto arr2 = new float[len];
    std::default_random_engine engine(clock());
    std::uniform_real_distribution<float> dist(-1, 1);
    for (size_t i = 0; i < len; ++i) {
        arr1[i] = dist(engine);
        arr2[i] = dist(engine);
    }

    timeDot(dotBaseline, "Baseline", arr1, arr2, len);
    timeDot(dotWinergrad, "Winergrad", arr1, arr2, len);
}

#endif //MATRIX_DOT_H
